/*
 * 代号：凤凰
 * http://www.jphenix.org
 * 2014-06-06
 * V4.0
 */
package com.jphenix.servlet.filter;

import com.jphenix.standard.docs.ClassInfo;

import javax.servlet.FilterConfig;
import javax.servlet.http.*;
import java.util.*;

/**
 * 页面提交的安全处理封装类
 * @author 刘虻
 * 2008-5-11下午09:25:01
 */
@ClassInfo({"2014-06-06 18:39","页面提交的安全处理封装类"})
public class SecureRequestWrapper 
			extends HttpServletRequestWrapper {

	protected FilterConfig filterConfig = null; //过滤器配置参数类
	
	//默认过滤字符 0段分割符  1小结分割符
	protected String defaultFilterChars = 
		"'1&#39;0<1&lt;0>1&gt;0%271&#39;0%3C1&lt;0%3E1&gt;0\"1&quot;0%221";
	protected String filterChars = null; //过滤字符
	protected ArrayList<String> keyList = null; //过滤字符序列
	protected ArrayList<String> valueList = null; //替换字符序列
	protected HttpServletRequest req = null; //封装后的核心类
	protected HttpServletResponse resp = null; //页面反馈
	protected Hashtable<String,String[]> parameterMap = null; //参数容器
	protected boolean disabled = false; //是否禁止过滤
	
	/**
	 * 构造函数
	 * 构造函数
	 * @author 刘虻
	 * @param req 页面请求
	 */
	public SecureRequestWrapper(HttpServletRequest req) {
		super(req);
		init(); //执行初始化方法
		this.req = req;
	}

	/**
	 * 设置是否禁止过滤
	 * 刘虻
	 * 2010-7-31 下午05:35:51
	 * @param disabled 是否禁止过滤
	 */
	public void setDisabled(boolean disabled) {
		this.disabled = disabled;
	}
	
	/**
	 * 构造函数
	 * 构造函数
	 * @author 刘虻
	 * @param req 页面请求
	 * @param filterConfig 配置信息容器
	 */
	public SecureRequestWrapper(
			HttpServletRequest req,FilterConfig filterConfig) {
		super(req);
		this.filterConfig = filterConfig;
		this.req = req;
		init(); //执行初始化方法
	}
	
	
	/**
	 * 从字符串序列转换为序列
	 * @author 刘虻
	 * 2007-5-30下午08:31:55
	 * @param source 源字符串
	 * @param point 分割符
	 * @return 转换后的序列
	 */
	protected ArrayList<String> splitToList(String source,String point) {
		if (source==null || source.length()==0) {
			return new ArrayList<String>();
		}
		//构造返回容器
		ArrayList<String> reArrl = new ArrayList<String>();
		while(true) {
			if (source==null) {
				source = "";
			}
			//获取分割点
			int splitPoint = source.indexOf(point);
			if (splitPoint<0) {
				reArrl.add(source);
				break;
			}
			reArrl.add(source.substring(0,splitPoint));
			//构造分割后的字符串
			source = 
				source.substring(splitPoint+point.length());
		}
		return reArrl;
	}
	
	
	
	/**
	 * 将字符串按照指定字符分割为字符串数组
	 * @author 刘虻
	 * 2006-10-26下午11:54:09
	 * @param source 原字符串
	 * @param splitStr 指定分割字符
	 * @return 分割后的字符串数组
	 */
	protected String[] split(String source,String splitStr) {
		//获取分割后的序列
		ArrayList<String> reArrl = splitToList(source,splitStr);
		//构件返回值
		String[] reStrs = new String[reArrl.size()];
		//复制值
		reArrl.toArray(reStrs);
		return reStrs;
	}
	
	/**
	 * 执行初始化方法
	 * @author 刘虻
	 * 2008-5-11下午09:32:16
	 */
	protected void init() {
		if (filterConfig==null) {
			filterChars = defaultFilterChars;
		}else {
			filterChars = 
				filterConfig
					.getInitParameter("SecureRequestFilterChars");
			if (filterChars==null || filterChars.length()==0) {
				filterChars = defaultFilterChars;
			}
		}
		keyList = new ArrayList<String>();
		valueList = new ArrayList<String>();
		//获取段序列
		ArrayList<String> subList = splitToList(filterChars,"0");
		for(String subStr:subList) {
			if (subStr==null || subStr.length()<1) {
				continue;
			}
			//获取过滤信息
			String[] element = split(subStr,"1");
			if (element==null) {
				continue;
			}
			keyList.add(element[0]);
			valueList.add(element[1]);
		}
	}
	
	/**
	 * 执行过滤
	 * @author 刘虻
	 * 2008-5-11下午10:09:58
	 * @param fixStr 被处理字符串
	 * @return 处理后的字符串
	 */
	protected String filterChar(String fixStr) {
		if (fixStr==null){
			return null;
		}
		try {
		    String key; //过滤关键字
			for (int i=0;i<keyList.size();i++) {
				key = keyList.get(i);
				if (key==null) {
					key = "";
				}
				//替换值
				String value = valueList.get(i);
				if (value==null) {
					value = "";
				}
				fixStr = fixStr.replaceAll(key,value);
			}
		}catch(Exception e) {
			e.printStackTrace();
			return "";
		}
		return fixStr;
	}
	
	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-5-11下午09:27:22
	 */
	@Override
    public String getQueryString() {
		if(disabled) {
			return req.getQueryString();
		}
		return filterChar(super.getQueryString());
	}
	
	
	
	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-5-11下午09:27:48
	 */
	@Override
    public String getParameter(String key) {
		if(disabled) {
			return req.getParameter(key);
		}
		return filterChar(super.getParameter(key));
	}
	
	
	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-5-11下午09:28:09
	 */
	@Override
    public String[] getParameterValues(String key) {
		if(disabled) {
			return req.getParameterValues(key);
		}
		//获取返回值
		String[] reStrs = super.getParameterValues(key);
		if (reStrs!=null) {
			for(int i=0;i<reStrs.length;i++) {
				reStrs[i] = filterChar(reStrs[i]);
			}
		}
		return reStrs;
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-5-13下午02:09:14
	 */
	public HttpServletRequest getKernel() {
		return req;
	}
	
	/**
	 * 设置页面反馈
	 * @author 刘虻
	 * 2008-6-21上午10:40:43
	 * @param response
	 */
	public void setResponse(HttpServletResponse response) {
		this.resp = response;
	}
	
	
	/**
	 * 获取页面反馈
	 * @author 刘虻
	 * 2008-6-21上午10:46:59
	 * @return 页面反馈
	 */
	public HttpServletResponse getResponse() {
		return resp;
	}
	
	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-5-11下午09:27:48
	 */
    @Override
    public Map<String,String[]> getParameterMap(){
		if(disabled) {
			return req.getParameterMap();
		}
		if(parameterMap==null){
			//获取未处理的原始参数容器
			Map<String,String[]> superMap = super.getParameterMap();
			//构造返回值
			parameterMap = new Hashtable<String,String[]>();
			if (superMap!=null){
				//获取主键管理类
				Set<String> keySet = superMap.keySet();
				if (keySet!=null){
					//获取主键迭代
					Iterator<String> keyIterator = keySet.iterator();
					if (keyIterator!=null){
						while(keyIterator.hasNext()){
							//获取主键元素
							String key = keyIterator.next();
							if (key==null) {
								key = "";
							}
							Object value = superMap.get(key); //主键值
							if (value!=null){
                                //构造新值
                                String[] tValue = new String[((String[])value).length];
                                for(int i=0;i<tValue.length;i++){
                                    //处理字符串
                                    tValue[i] = filterChar(((String[])value)[i]);
                                }
                                parameterMap.put(key, tValue);
							}
						}
					}
				}
			}
		}
		return parameterMap;
	}
	

//	/**
//	 * 无用,以前用来处理会话丢失问题,但实际没有作用
//	 * 覆盖方法
//	 * @author 刘虻
//	 * 2008-6-21上午10:41:20
//	 */
//	public HttpSession getSession() {
//			HttpSession session = super.getSession();
//			processSessionCookie(session); //处理会话主键
//			return session;
//	}
//	
	
	/**
	 * 无用,以前用来处理会话丢失问题,但实际没有作用
	 * 这种方法不可取,因为JSESSIONID名字可以通过weblogic中配置,一旦修改了这个名字,这个方法就无效了
	 * 甚至还干扰程序
	 * 处理会话主键
	 * @author 刘虻
	 * 2008-6-21上午10:44:39
	 * @param session 会话对象
	 */
	protected void processSessionCookie(HttpSession session) {
		if (null==resp || null==session) {
			return;
		}
		//cookieOverWritten - 用于过滤多个Set-Cookie头的标志
		Object cookieOverWritten = 
				getAttribute("COOKIE_OVERWRITTEN_FLAG");
		if (null==cookieOverWritten 
				&& isSecure() 
				&& isRequestedSessionIdFromCookie() 
				&& session.isNew()) {
			//当是https协议，且新session时，创建JSESSIONID cookie以欺骗浏览器
			Cookie cookie = new Cookie("JSESSIONID", session.getId());
			cookie.setMaxAge(-1); // 有效时间为浏览器打开或超时
			String contextPath = getContextPath(); //上下文路径
			if ((contextPath != null) && (contextPath.length() > 0)) {
				cookie.setPath(contextPath);
			} else {
				cookie.setPath("/");
			}
			resp.addCookie(cookie); // 增加一个Set-Cookie头到response
			setAttribute("COOKIE_OVERWRITTEN_FLAG", "true");// 过滤多个Set-Cookie头的标志
		}
	}
}
